/*
 * @Author: your name
 * @Date: 2021-05-29 21:22:04
 * @LastEditTime: 2022-04-17 11:03:20
 * @LastEditors: Please set LastEditors
 * @Description: GUI引擎抽象层，实现awtk接口解耦合，该文件为awtk对外api的唯一接口文件，
 * 不得绕过该文件直接调用awtk接口。
 * @FilePath: \telescope720P\src\gui_engine.h
 */
#ifndef GUI_ENGINE_H
#define GUI_ENGINE_H
#include "gui_function.h"
#include <functional>
#include <iostream>
#include <memory>
#if defined(WIN32) && !defined(MINGW)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#endif
class Widget {
public:
    virtual ~Widget() { }
    /**
     * @brief
     * 创建的控件是否有效
     * @return true
     * @return false
     */
    virtual bool IsValid() { return false; }
    virtual std::string Name() { return "null"; }
    virtual void SetWidget(Widget* p) { }
    virtual int GetCoordX() { return 0; }
    virtual int GetCoordY() { return 0; }
};
using KeyDownEventCallback = std::function<void(KeyboardValue)>;
class ContextDate {
public:
};
class Context {
public:
    std::unique_ptr<Widget> widget;
    void (*eventCallback)(void*);
    bool (*timerCallback)(void*);
    KeyCmd cmd;
    /**
     * @brief
     * ctx 只负责传递，不负责管理
     */
    void* ctx;

public:
    Context()
    {
        eventCallback = nullptr;
        ctx = nullptr;
        cmd = KeyCmd::KEY_CMD_DEFAULT;
    }
    virtual ~Context()
    {
    }
    virtual int Type() { return 0; }
    void WidgetReset(Widget* p)
    {
        widget.reset(p);
    }
    template <typename T>
    bool GetData(T& value)
    {
        if (ctx) {
            value = *(T*)(ctx);
            return true;
        } else {
            return false;
        }
    }
};
/**
 * @brief
 * 模板类：使用模板类型数据，不使用指针数据类型，减少维护压力
 * @tparam T
 */
template <typename T>
class ContextV2 : public Context {
public:
    /**
     * @brief
     * 数据
     */
    T data;

public:
    ContextV2(T value)
        : data(value)
    {
    }
    virtual ~ContextV2() = default;
    /**
     * @brief
     * 可以拓展用于判断数据的自定义类型。暂未使用
     * @return int
     */
    // virtual int Type() { return 0; }
};

template <typename T, typename T2>
class ContextV5 : public Context {
public:
    /**
     * @brief
     * 数据
     */
    T data;
    T2 display;

public:
    ContextV5(T value, T2 str)
        : data(value)
        , display(str)
    {
    }
    virtual ~ContextV5() = default;
    /**
     * @brief
     * 可以拓展用于判断数据的自定义类型。暂未使用
     * @return int
     */
    // virtual int Type() { return 0; }
};

/**
 * @brief
 * 事件枚举，与awtk事件一一对应，为了实现与awtk源码解耦合，枚举名称与awtk一样；
 * 注意此处新增事件时要同步awtk事件数组evtMap
 */
enum class WidgitOnEvent {
    EVT_WINDOW_CLOSE = 0,
    EVT_WINDOW_TO_BACKGROUND,
    EVT_WINDOW_TO_FOREGROUND,
    EVT_END
};
/**
 * @brief
 * 为了实现与awtk解耦合，该结构体从awtk拷贝；
 * 如出现异常，优先排查awtk是否已经发生修改
 */
enum class DrawType {
    /**
     * @const IMAGE_DRAW_DEFAULT
     * 缺省显示。将图片按原大小显示在目标矩形的左上角。
     */
    IMAGE_DRAW_DEFAULT = 0,

    /**
     * @const IMAGE_DRAW_CENTER
     * 居中显示。将图片按原大小显示在目标矩形的中央。
     */
    IMAGE_DRAW_CENTER,

    /**
     * @const IMAGE_DRAW_ICON
     * 图标显示。同居中显示，但会根据屏幕密度调整大小。
     */
    IMAGE_DRAW_ICON,

    /**
     * @const IMAGE_DRAW_SCALE
     * 缩放显示。将图片缩放至目标矩形的大小(不保证宽高成比例)。
     */
    IMAGE_DRAW_SCALE,

    /**
     * @const IMAGE_DRAW_SCALE_AUTO
     * 自动缩放显示。将图片缩放至目标矩形的宽度或高度(选取最小的比例)，并居中显示。
     */
    IMAGE_DRAW_SCALE_AUTO,

    /**
     * @const IMAGE_DRAW_SCALE_DOWN
     * 如果图片比目标矩形大，自动缩小显示，否则居中显示。
     */
    IMAGE_DRAW_SCALE_DOWN,

    /**
     * @const IMAGE_DRAW_SCALE_W
     * 宽度缩放显示。 将图片缩放至目标矩形的宽度，高度按此比例进行缩放，超出不部分不显示。
     */
    IMAGE_DRAW_SCALE_W,

    /**
     * @const IMAGE_DRAW_SCALE_H
     * 高度缩放显示。将图片缩放至目标矩形的高度，宽度按此比例进行缩放，超出不部分不显示。
     */
    IMAGE_DRAW_SCALE_H,

    /**
     * @const IMAGE_DRAW_REPEAT
     * 平铺显示。
     */
    IMAGE_DRAW_REPEAT,

    /**
     * @const IMAGE_DRAW_REPEAT_X
     * 水平方向平铺显示，垂直方向缩放。
     */
    IMAGE_DRAW_REPEAT_X,
    /**
     * @const IMAGE_DRAW_REPEAT_Y
     * 垂直方向平铺显示，水平方向缩放。
     */
    IMAGE_DRAW_REPEAT_Y,
    /**
     * @const IMAGE_DRAW_REPEAT_Y_INVERSE
     * 垂直方向平铺显示，水平方向缩放(从底部到顶部)。
     */
    IMAGE_DRAW_REPEAT_Y_INVERSE,

    /**
     * @const IMAGE_DRAW_PATCH9
     * 9宫格显示。
     * 将图片分成等大小的9块，4个角按原大小显示在目标矩形的4个角，左右上下和中间5块分别缩放显示在对应的目标区域。
     */
    IMAGE_DRAW_PATCH9,

    /**
     * @const IMAGE_DRAW_PATCH3_X
     * 水平方向3宫格显示，垂直方向居中显示。
     * 将图片在水平方向上分成等大小的3块，左右两块按原大小显示在目标矩形的左右，中间一块缩放显示在目标区域中间剩余部分。
     */
    IMAGE_DRAW_PATCH3_X,

    /**
     * @const IMAGE_DRAW_PATCH3_Y
     * 垂直方向3宫格显示，水平方向居中显示。
     * 将图片在垂直方向上分成等大小的3块，上下两块按原大小显示在目标矩形的上下，中间一块缩放显示在目标区域中间剩余部分。
     */
    IMAGE_DRAW_PATCH3_Y,

    /**
     * @const IMAGE_DRAW_PATCH3_X_SCALE_Y
     * 水平方向3宫格显示，垂直方向缩放显示。
     * 将图片在水平方向上分成等大小的3块，左右两块按原大小显示在目标矩形的左右，中间一块缩放显示在目标区域中间剩余部分。
     */
    IMAGE_DRAW_PATCH3_X_SCALE_Y,

    /**
     * @const IMAGE_DRAW_PATCH3_Y_SCALE_X
     * 垂直方向3宫格显示，水平方向缩放显示。
     * 将图片在垂直方向上分成等大小的3块，上下两块按原大小显示在目标矩形的上下，中间一块缩放显示在目标区域中间剩余部分。
     */
    IMAGE_DRAW_PATCH3_Y_SCALE_X,

    /**
     * @const IMAGE_DRAW_REPEAT9
     * 平铺9宫格显示。
     * 将图片分成4个角和5块平铺块，4个角按原大小显示在目标矩形的4个角，其余5块会平铺对应的目标区域。
     * 切割方法为（如下图）：
     * 如果图片宽度为奇数，则中间一块为一列数据，如果图片宽度为偶数，则中间一块为二列数据，其他数据分为左右块
     * 如果图片高度为奇数，则中间一块为一行数据，如果图片高度为偶数，则中间一块为二行数据，其他数据分为上下块
     * 中间一块数据根据上面两条规则组成4中情况，分别是一列一行数据，一列两行数据，两列一行数据和两行两列数据
     */
    IMAGE_DRAW_REPEAT9,

    /**
     * @const IMAGE_DRAW_REPEAT3_X
     * 水平方向3宫格显示，垂直方向居中显示。
     * 将图片在水平方向上分成左右相等两块和中间一块，如果图片宽度为奇数，则中间一块为一列数据，如果图片宽度为偶数，则中间一块为二列数据，其他数据分为左右块。
     * 左右两块按原大小显示在目标矩形的左右，中间一列像素点平铺显示在目标区域中间剩余部分。
     */
    IMAGE_DRAW_REPEAT3_X,

    /**
     * @const IMAGE_DRAW_REPEAT3_Y
     * 垂直方向3宫格显示，水平方向居中显示。
     * 将图片在垂直方向上分成上下相等两块和中间一块，如果图片高度为奇数，则中间一块为一行数据，如果图片高度为偶数，则中间一块为二行数据，其他数据分为上下块
     * 上下两块按原大小显示在目标矩形的上下，中间一块平铺显示在目标区域中间剩余部分。
     */
    IMAGE_DRAW_REPEAT3_Y
};
class GuiEngine {
public:
    static GuiEngine& GetInstance(std::shared_ptr<GuiEngine> *ins = nullptr)
    {
        static std::shared_ptr<GuiEngine> guiEngine = std::make_shared<GuiEngine>();
        if (ins) {
            guiEngine  = *ins;
        }
        return *guiEngine.get();
    }
    // static void SetInstance(GuiEngine* p)
    // {
    //     if (instance) {
    //         delete instance;
    //     }
    //     instance = p;
    // }
    /**
     * @brief
     * 抽象类实例化，T为该抽象类的实现类。
     * @tparam T
     */
    // template <typename T>
    // static void VeritableInstance()
    // {
    //     if (instance) {
    //         delete instance;
    //     }
    //     instance = new T;
    // }
    GuiEngine() { }
    virtual ~GuiEngine()
    {
        // if (instance)
        // {
        //     delete instance;
        // }
    }
#if defined(WIN32) && !defined(MINGW)
    /**
     * @brief
     * windows平台的初始化函数，启动并初始化UI引擎库。
     * @param lpcmdline
     * @return true
     * @return false
     */
    virtual bool Init(LPWSTR lpcmdline, void (*appInit)())
    {
        return false;
    }
#else
    /**
     * @brief
     * 嵌入式Linux系统使用的初始化函数
     * @param width 显示的宽度（一般是屏幕像素宽度）
     * @param height 显示的高度（一般是屏幕像素高度）
     * @param resPath 资源在系统的绝对路径，一般由系统工程师确认。
     * @param appInit UI界面初始化回调函数，在awtk线程处理，避免出现白屏闪现问题。
     * @return true
     * @return false
     */
    virtual bool Init(unsigned int width, unsigned int height, std::string resPath, void (*appInit)()) { return false; }
#endif
    virtual void UnInit()
    {
    }
    virtual Widget* NewWidget() { return nullptr; }
    virtual void RegisterKeyDownEvent(void (*event)(KeyboardValue value)) { }
    virtual Widget* WindowOpen(std::string windowName) { return nullptr; }
    virtual bool WindowClose(Widget* info) { return false; };
    virtual bool IdleQueue(void* ctx) { return false; }
    virtual bool TimerQueue(void* ctx, unsigned int duration) { return false; }
    virtual unsigned int TimerAdd(void* ctx, unsigned int duration) { return 0; }
    virtual unsigned int TimerCount() { return 0; }
    virtual bool TimerModiy(unsigned int timerId, unsigned int duration) { return false; }
    virtual bool Lookup(Widget* info, const char* name, bool recursive, Widget* value) { return false; }
    virtual bool SlideMenuSetValue(Widget* widget, unsigned int value) { return false; }
    virtual bool UseStyle(Widget* info, const char* style) { return false; }
    virtual bool SetTrText(Widget* info, const char* trText) { return false; }
    virtual bool SetText(Widget* info, const char* text) { return false; }
    virtual bool SetTextUtf8(Widget* info, const char* text) { return false; }
    virtual bool GetTextUtf8(Widget* info, char* text, unsigned int size) { return false; }
    virtual bool CreateAnimator(Widget* info, const char* animation) { return false; }
    virtual bool SetVisible(Widget* info, bool visible) { return false; }
    virtual bool ViewCreate(Widget* info, int x, int y, int w, int h, Widget* value) { return false; }
    virtual bool LabelCreate(Widget* info, int x, int y, int w, int h, Widget* value) { return false; }
    virtual bool SetSelfLayout(Widget* info, const char* params) { return false; }
    virtual bool SetChildrenLayout(Widget* info, const char* params) { return false; }
    virtual bool SetName(Widget* info, const char* name) { return false; }
    virtual bool Destroy(Widget* info) { return false; }
    virtual bool Move(Widget* info, int x, int y) { return false; }
    virtual bool SliderSetValue(Widget* info, double value) { return false; }
    virtual bool CreateImage(Widget* info, int x, int y, unsigned int w, unsigned int h, Widget* value) { return false; }
    virtual bool SetImage(Widget* info, const char* name) { return false; }
    /**
     * @brief
     * 该函数有一个潜在隐患，这里为了解耦合，需要对绘制类型进行转换，如果awtk修改了绘制类型，可能会出现绘制类型转换bug
     * @param info
     * @param drawType
     * @return true
     * @return false
     */
    virtual bool ImageSetDrawType(Widget* info, DrawType drawType) { return false; }
    /**
     * @brief
     * 读取译文
     * @param trText 译文名称
     * @param outText 出参：译文内容
     * @return true
     * @return false
     */
    virtual bool LocaleInfoTr(const char* trText, char** outText) { return false; }
    virtual bool LanguageChange(const char* language) { return false; }
    virtual bool EditSetFocus(Widget* info, bool focus) { return false; }
    virtual bool EditSetCursor(Widget* info, unsigned int cursor) { return false; }
    virtual bool EditSetReadOnly(Widget* info, bool readOnly) { return false; }
    virtual bool EditSetTrTips(Widget* info, const char* trTips) { return false; }
    virtual bool SetFloating(Widget* info, bool floating) { return false; }
    virtual unsigned int WidgetOn(Widget* info, WidgitOnEvent evt, Context* ctx) { return false; }
    virtual bool SetLineWrap(Widget* info, bool wrap) { return false; }
    virtual bool SetWordWrap(Widget* info, bool wrap) { return false; }
    virtual bool LabelSetLength(Widget* info, int length) { return false; }
    virtual bool HscrollLabelCreate(Widget* info, int x, int y, int w, int h, Widget* value) { return false; }
    virtual bool HscrollLabelSetDuration(Widget* info, int duration) { return false; }
    virtual bool HscrollLabelSetElipses(Widget* info, bool ellipses) { return false; }
    virtual bool HscrollLabelSetLoop(Widget* info, bool loop) { return false; }
    virtual bool HscrollLabelSetLull(Widget* info, bool lull) { return false; }
    virtual bool HscrollLabelSetOnlyFocus(Widget* info, bool onlyFocus) { return false; }
    virtual bool HscrollLabelSetOnlyParentFocus(Widget* info, bool onlyFocus) { return false; }
    virtual bool HscrollLabelStop(Widget* value) { return false; }
    virtual bool SetFocus(Widget* info, bool focus) { return false; }
    virtual bool MainLoopPostKeyEvent(bool press, KeyboardValue key) { return false; }
    virtual bool DestroyChildren(Widget* info) { return false; }
    virtual bool MleditSetCursor(Widget* info, unsigned int cursor) { return false; }
    virtual bool MleditSetFocus(Widget* info, bool focus) { return false; }
    virtual bool MleditSetOpenImWhenFocused(Widget* info, bool open) { return true; }
    virtual bool DigitClockCreate(Widget* info, int x, int y, int w, int h, Widget* value) { return false; }
    virtual bool DigitClockSetFormat(Widget* info, const std::string& format) { return true; }
private:
    /**
     * @brief
     * 该指针由内部管理。
     */
    // static GuiEngine* instance;
};
void CreateGuiAwtkInstance();
#endif